#include "GameState.h"

GameState::GameState(void)
{
	m_MoveSpeed = 1.0f;
	m_RotateSpeed = 0.3f;

	m_pCamera = 0;
	m_pSceneMgr = 0;
	m_pRaySceneQuery = 0;
	m_FrameEvent = Ogre::FrameEvent();

	m_bRMousePressed = false;
	m_bLMousePressed = false;
	m_bShowGrid = true;
	m_bExit = false;
}

void GameState::enter(void)
{
	OgreSK::getSingletonPtr()->m_pLog->logMessage("Entering state: GameState");

	m_pSceneMgr = OgreSK::getSingletonPtr()->m_pRoot->createSceneManager(Ogre::ST_GENERIC);
	m_pSceneMgr->setAmbientLight(Ogre::ColourValue(0.2f, 0.2f, 0.2f));

	m_pRaySceneQuery = m_pSceneMgr->createRayQuery(Ogre::Ray());

	m_pCamera = m_pSceneMgr->createCamera("Camera");
	m_pCamera->setPosition(Ogre::Vector3(0, 50, 50));
	m_pCamera->lookAt(Ogre::Vector3(0, 0, 0));
	m_pCamera->setNearClipDistance(1);
	
	if(OgreSK::getSingletonPtr()->m_pRoot->getRenderSystem()->getCapabilities()->hasCapability(Ogre::RSC_INFINITE_FAR_PLANE))
		m_pCamera->setFarClipDistance(0);
	else
		m_pCamera->setFarClipDistance(50000);

	m_pCamera->setAspectRatio(Ogre::Real(OgreSK::getSingletonPtr()->m_pViewport->getActualWidth()) / Ogre::Real(OgreSK::getSingletonPtr()->m_pViewport->getActualHeight()));
	OgreSK::getSingletonPtr()->m_pViewport->setCamera(m_pCamera);

	buildGUI();

	createScene();
}

void GameState::createScene(void)
{
	Ogre::Vector3 lightdir(0.55, -0.3, 0.75);
	lightdir.normalise();
 
	Ogre::Light* light = m_pSceneMgr->createLight("SunLight");
	light->setType(Ogre::Light::LT_DIRECTIONAL);
	light->setDirection(lightdir);
	light->setDiffuseColour(Ogre::ColourValue::White);
	light->setSpecularColour(Ogre::ColourValue(0.4, 0.4, 0.4));

	Ogre::Entity *test = m_pSceneMgr->createEntity("TestEnt", "cube.mesh");
	Ogre::SceneNode *testNode = m_pSceneMgr->getRootSceneNode()->createChildSceneNode("TestNode");
	testNode->attachObject(test);
	testNode->setPosition(-1000, 0, 0);

	manageTerrain(light);

	grid = new Helper::Grid(m_pSceneMgr);
	grid->CreateGrid(20, 2000.0f, 2000.0f, 513);
	m_pSceneMgr->getRootSceneNode()->attachObject(grid->m_pGrid);
	grid->setVisible(m_bShowGrid);

	new DOF::GameObjectManager();

	m_pSelectedObject = new Runway(1, Ogre::Vector3::ZERO, Ogre::Quaternion::ZERO, "Runway", m_pSceneMgr);
}

void GameState::manageTerrain(Ogre::Light *light)
{
	m_pTerrainGlobals = new Ogre::TerrainGlobalOptions();

	m_pTerrainGroup = new Ogre::TerrainGroup(m_pSceneMgr, Ogre::Terrain::ALIGN_X_Z, 513, 2000.0f);
	m_pTerrainGroup->setFilenameConvention(Ogre::String("osairportTerrain"), Ogre::String("dat"));
	m_pTerrainGroup->setOrigin(Ogre::Vector3::ZERO);

	configureTerrainDefaults(light);

	for(long x = 0; x <= 0; x++)
		for(long y = 0; y <= 0; y++)
			defineTerrain(x, y);

	m_pTerrainGroup->loadAllTerrains(true);

	if(m_bIsImported)
	{
		Ogre::TerrainGroup::TerrainIterator i = m_pTerrainGroup->getTerrainIterator();

		while(i.hasMoreElements())
		{
			Ogre::Terrain *terrain = i.getNext()->instance;
			initBlendMaps(terrain);
		}
	}

	m_pTerrainGroup->freeTemporaryResources();
}

void GameState::configureTerrainDefaults(Ogre::Light *light)
{
	m_pTerrainGlobals->setMaxPixelError(8);
	m_pTerrainGlobals->setCompositeMapDistance(3000);
	m_pTerrainGlobals->setLightMapDirection(light->getDerivedDirection());
	m_pTerrainGlobals->setCompositeMapAmbient(m_pSceneMgr->getAmbientLight());
	m_pTerrainGlobals->setCompositeMapDiffuse(light->getDiffuseColour());

	Ogre::Terrain::ImportData& defaultimp = m_pTerrainGroup->getDefaultImportSettings();
	defaultimp.terrainSize = 513;
	defaultimp.worldSize = 12000.0f;
	defaultimp.inputScale = 600;
	defaultimp.minBatchSize = 33;
	defaultimp.maxBatchSize = 65;

	defaultimp.layerList.resize(1);
	defaultimp.layerList[0].worldSize = 30;
	defaultimp.layerList[0].textureNames.push_back("grass_green-01_diffusespecular.dds");
	defaultimp.layerList[0].textureNames.push_back("grass_green-01_normalheight.dds");
}

void GameState::defineTerrain(long x, long y)
{
	Ogre::String filename = m_pTerrainGroup->generateFilename(x, y);
	if (Ogre::ResourceGroupManager::getSingletonPtr()->resourceExists(m_pTerrainGroup->getResourceGroup(), filename))
	{
		m_pTerrainGroup->defineTerrain(x, y);
	}
	else
	{
		m_pTerrainGroup->defineTerrain(x, y, 0.0f);
		m_bIsImported = true;
	}
}

void GameState::initBlendMaps(Ogre::Terrain *terrain)
{

}

void GameState::buildGUI(void)
{
	OgreSK::getSingletonPtr()->m_pTrayMgr->showFrameStats(OgreBites::TL_BOTTOMLEFT);

	Ogre::StringVector items;
	items.push_back("cam.pX");
	items.push_back("cam.pY");
	items.push_back("cam.pZ");
	items.push_back("mouse.X");
	items.push_back("mouse.Y");

	m_pDetailsPanel = OgreSK::getSingletonPtr()->m_pTrayMgr->createParamsPanel(OgreBites::TL_TOPLEFT, "DetailsPanel", 200, items);
	m_pDetailsPanel->show();

	Ogre::StringVector chatModes;
	chatModes.push_back("Solid mode");
	chatModes.push_back("Wireframe mode");
	chatModes.push_back("Point mode");
	OgreSK::getSingletonPtr()->m_pTrayMgr->createLongSelectMenu(OgreBites::TL_TOPRIGHT, "ChatModeSelMenu", "ChatMode", 200, 3, chatModes);
}

void GameState::itemSelected(OgreBites::SelectMenu* menu)
{
	switch(menu->getSelectionIndex())
	{
	case 0:
		m_pCamera->setPolygonMode(Ogre::PM_SOLID);
		break;
	case 1:
		m_pCamera->setPolygonMode(Ogre::PM_WIREFRAME);
		break;
	case 2:
		m_pCamera->setPolygonMode(Ogre::PM_POINTS);
		break;
	}
}

void GameState::exit(void)
{
	OgreSK::getSingletonPtr()->m_pLog->logMessage("Leaving state: GameState");

	m_pSceneMgr->destroyQuery(m_pRaySceneQuery);
	m_pSceneMgr->destroyCamera(m_pCamera);
	if(m_pSceneMgr)
		OgreSK::getSingletonPtr()->m_pRoot->destroySceneManager(m_pSceneMgr);
}

void GameState::update(double timeSinceLastFrame)
{
	m_FrameEvent.timeSinceLastFrame = timeSinceLastFrame;
	OgreSK::getSingletonPtr()->m_pTrayMgr->frameRenderingQueued(m_FrameEvent);

	if(m_bExit)
	{
		popState();
		return;
	}

	m_pDetailsPanel->setParamValue(0, Ogre::StringConverter::toString(m_pCamera->getDerivedPosition().x));
	m_pDetailsPanel->setParamValue(1, Ogre::StringConverter::toString(m_pCamera->getDerivedPosition().y));
	m_pDetailsPanel->setParamValue(2, Ogre::StringConverter::toString(m_pCamera->getDerivedPosition().z));
	m_pDetailsPanel->setParamValue(3, Ogre::StringConverter::toString(OgreSK::getSingletonPtr()->m_pMouse->getMouseState().X.abs));
	m_pDetailsPanel->setParamValue(4, Ogre::StringConverter::toString(OgreSK::getSingletonPtr()->m_pMouse->getMouseState().Y.abs));

	m_MoveScale = m_MoveSpeed * timeSinceLastFrame;
	m_RotateScale = m_RotateSpeed * timeSinceLastFrame;

	moveCamera();
}

void GameState::moveCamera(void)
{
	m_Translate = Ogre::Vector3::ZERO;

	if(OgreSK::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_W))
		m_Translate.z -= m_MoveScale;
	if(OgreSK::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_S))
		m_Translate.z += m_MoveScale;
	if(OgreSK::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_A))
		m_Translate.x -= m_MoveScale;
	if(OgreSK::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_D))
		m_Translate.x += m_MoveScale;

	if(OgreSK::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_LSHIFT))
		m_pCamera->moveRelative(m_Translate);

	m_pCamera->moveRelative(m_Translate / 10);

	Ogre::Vector3 camPos = m_pCamera->getPosition();
	Ogre::Ray cameraRay(Ogre::Vector3(camPos.x, 5000.0f, camPos.z), Ogre::Vector3::NEGATIVE_UNIT_Y);
	m_pRaySceneQuery->setRay(cameraRay);

	Ogre::RaySceneQueryResult &result = m_pRaySceneQuery->execute();
	Ogre::RaySceneQueryResult::iterator i = result.begin();

	if(i != result.end() && i->movable && i->movable->getName() == "GroundEntity")
	{
	}
}

bool GameState::keyReleased(const OIS::KeyEvent &evt)
{
	OgreSK::getSingletonPtr()->keyReleased(evt);
	return true;
}

bool GameState::keyPressed(const OIS::KeyEvent &evt)
{
	if(OgreSK::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_ESCAPE))
	{
		m_bExit = true;
		return true;
	}
	else if(OgreSK::getSingletonPtr()->m_pKeyboard->isKeyDown(OIS::KC_I))
	{
		m_bShowGrid = m_bShowGrid ? false : true;
		grid->setVisible(m_bShowGrid);
		return true;
	}

	OgreSK::getSingletonPtr()->keyPressed(evt);
	return true;
}

bool GameState::mouseMoved(const OIS::MouseEvent &evt)
{
	if(OgreSK::getSingletonPtr()->m_pTrayMgr->injectMouseMove(evt)) return true;

	if(m_bRMousePressed)
	{
		m_pCamera->yaw(Ogre::Degree(evt.state.X.rel * -0.1f));
		m_pCamera->pitch(Ogre::Degree(evt.state.Y.rel * -0.1f));
	}
	else
	{
		CEGUI::Point mousePos = CEGUI::MouseCursor::getSingletonPtr()->getPosition();
		Ogre::Ray mouseRay = m_pCamera->getCameraToViewportRay(mousePos.d_x / float(evt.state.width), mousePos.d_y / float(evt.state.height));
		m_pRaySceneQuery->setRay(mouseRay);

		Ogre::RaySceneQueryResult &result = m_pRaySceneQuery->execute();
		Ogre::RaySceneQueryResult::iterator itr = result.begin();

		if(itr != result.end() && itr->worldFragment)
			m_pSelectedObject->translate(itr->worldFragment->singleIntersection);
	}

	return true;
}

bool GameState::mousePressed(const OIS::MouseEvent &evt, OIS::MouseButtonID id)
{
	if(OgreSK::getSingletonPtr()->m_pTrayMgr->injectMouseDown(evt, id)) return true;

	if(id == OIS::MB_Left)
		m_bLMousePressed = true;
	if(id == OIS::MB_Right)
		m_bRMousePressed = true;

	return true;
}

bool GameState::mouseReleased(const OIS::MouseEvent &evt, OIS::MouseButtonID id)
{
	if(OgreSK::getSingletonPtr()->m_pTrayMgr->injectMouseUp(evt, id)) return true;

	if(id == OIS::MB_Left)
		m_bLMousePressed = false;
	if(id == OIS::MB_Right)
		m_bRMousePressed = false;

	return true;
}
